package com.central.apps.service.impl;

import cn.hutool.core.map.MapUtil;
import com.central.app.service.HandlerService;
import com.central.apps.dao.EsFileRepository;
import com.central.apps.entity.EsFile;
import com.central.apps.service.EsFileService;
import com.central.common.auth.details.LoginAppUser;
import com.central.common.util.SysUserUtil;
import com.central.common.web.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.PDFTextStripper;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.*;

/**
 * es文件服务impl
 *
 * @author JHY
 * @date 2022/11/10
 */
@Slf4j
@Service
public class EsFileServiceImpl implements EsFileService {
    @Resource
    private EsFileRepository repository;
    @Resource
    private HandlerService handlerService;
    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Override
    public void importAllDoc() {
        log.info(" =====> Start import all Document <===== ");
        System.out.println(" =====> Start import all Document <===== ");
        List<Map<String, Object>> fileList = handlerService.findBySql("select * from tb_file");
        for (Map<String, Object> map : fileList) {
            String fileid = MapUtil.getStr(map, "fileid");
            String pathid = MapUtil.getStr(map, "pathid");
            String deptid = MapUtil.getStr(map, "deptid");
            String deptfullname = MapUtil.getStr(map, "deptfullname");
            String userid = MapUtil.getStr(map, "userid");
            String username = MapUtil.getStr(map, "username");
            String uploadtime = MapUtil.getStr(map, "uploadtime");
            String filesize = MapUtil.getStr(map, "filesize");
            String filepath = MapUtil.getStr(map, "filepath");
            String extensionname = MapUtil.getStr(map, "extensionname");
            String appid = MapUtil.getStr(map, "appid");
            String appname = MapUtil.getStr(map, "appname");
            String recordid = MapUtil.getStr(map, "recordid");
            String filestatus = MapUtil.getStr(map, "filestatus");
            String statustime = MapUtil.getStr(map, "statustime");
            String filename = MapUtil.getStr(map, "filename");
            String filerealname = MapUtil.getStr(map, "filerealname");
            String fileversion = MapUtil.getStr(map, "fileversion");
            String md5 = MapUtil.getStr(map, "md5");
            String isshow = MapUtil.getStr(map, "isshow");

            List<Map<String, Object>> pathList = handlerService.findBySql("select * from tb_path where pathid = " + pathid + "");
            String parentname = MapUtil.getStr(pathList.get(0), "parentname");
            String downloadurl = parentname + filepath;
            System.out.println(downloadurl);
            String filecontent = EsFileServiceImpl.readFile(extensionname, downloadurl);

            EsFile file = new EsFile();
            file.setFileid(fileid);
            file.setPathid(pathid);
            file.setDeptid(deptid);
            file.setDeptfullname(deptfullname);
            file.setUserid(userid);
            file.setUsername(username);
            file.setUploadtime(uploadtime);
            file.setFilesize(filesize);
            file.setFilepath(filepath);
            file.setExtensionname(extensionname);
            file.setAppid(appid);
            file.setAppname(appname);
            file.setRecordid(recordid);
            file.setFilestatus(filestatus);
            file.setStatustime(statustime);
            file.setFilename(filename);
            file.setFilerealname(filerealname);
            file.setFileversion(fileversion);
            file.setMd5(md5);
            file.setIsshow(isshow);
            file.setDownloadurl(downloadurl);
            if (StringUtils.isNotBlank(filecontent)) {
                file.setFilecontent(filecontent);
            }
            try {
                repository.save(file);
            } catch (Exception e) {
                System.out.println(" ==> 插入失败 :" + e.getMessage());
                continue;
            }
            System.out.println(" =====> 插入完成 <===== fileid:" + fileid);
        }
        log.info(" =====> End import all Document <===== ");
        System.out.println(" =====> End import all Document <===== ");
    }

    @Override
    public void deleteAllDoc() {
        log.info(" =====> Start delete all Document <=====");
        try {
            repository.deleteAll();
        } catch (Exception e) {
            System.out.println(e);
            log.error(e.getMessage());
        }
        log.info(" =====> End delete all Document <=====");
    }

    @Override
    public Map<String, Object> queryDoc(Map<String, Object> map) {
        LoginAppUser loginAppUser = SysUserUtil.getLoginAppUser();
        Long id = loginAppUser.getId();
        // 搜索关键字
        String keywords = MapUtil.getStr(map, "keywords");
        // 1. 创建搜索请求
        SearchRequest searchRequest = new SearchRequest(EsFile.INDEX);
        // 2. 创建搜索对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //3、高亮构造器
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        BoolQueryBuilder bool = new BoolQueryBuilder();
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("userid", id);
        bool.must(matchQuery);
        if (StringUtils.isNotBlank(keywords)) {
            bool.must(QueryBuilders.multiMatchQuery(keywords, "filename", "filecontent"));
        }
        System.out.println(bool);


        highlightBuilder.preTags("<font style='color: red'>");
        highlightBuilder.postTags("</font>");
        highlightBuilder.field("filecontent");
        //同一字段中存在多个高亮值 设置都高亮
        highlightBuilder.requireFieldMatch(true);
        searchSourceBuilder.highlighter(highlightBuilder);

        searchSourceBuilder.query(bool);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<Object> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlightTitle = highlightFields.get("filecontent");
            //替换
            if (highlightTitle != null) {
                Text[] fragments = highlightTitle.getFragments();
                if (fragments != null && fragments.length > 0) {
                    sourceMap.replace("filecontent", fragments[0].toString());
                }
            }

            EsFile file = new EsFile();
            file.setFileid(MapUtil.getStr(sourceMap, "fileid"));
            file.setPathid(MapUtil.getStr(sourceMap, "pathid"));
            file.setDeptid(MapUtil.getStr(sourceMap, "deptid"));
            file.setDeptfullname(MapUtil.getStr(sourceMap, "deptfullname"));
            file.setUserid(MapUtil.getStr(sourceMap, "userid"));
            file.setUsername(MapUtil.getStr(sourceMap, "username"));
            file.setUploadtime(MapUtil.getStr(sourceMap, "uploadtime"));
            file.setFilesize(MapUtil.getStr(sourceMap, "filesize"));
            file.setFilepath(MapUtil.getStr(sourceMap, "filepath"));
            file.setExtensionname(MapUtil.getStr(sourceMap, "extensionname"));
            file.setAppid(MapUtil.getStr(sourceMap, "appid"));
            file.setAppname(MapUtil.getStr(sourceMap, "appname"));
            file.setRecordid(MapUtil.getStr(sourceMap, "recordid"));
            file.setFilestatus(MapUtil.getStr(sourceMap, "filestatus"));
            file.setStatustime(MapUtil.getStr(sourceMap, "statustime"));
            file.setFilename(MapUtil.getStr(sourceMap, "filename"));
            file.setFilerealname(MapUtil.getStr(sourceMap, "filerealname"));
            file.setFileversion(MapUtil.getStr(sourceMap, "fileversion"));
            file.setMd5(MapUtil.getStr(sourceMap, "md5"));
            file.setIsshow(MapUtil.getStr(sourceMap, "isshow"));
            file.setDownloadurl(MapUtil.getStr(sourceMap, "downloadurl"));
            file.setFilecontent(MapUtil.getStr(sourceMap, "filecontent"));

            list.add(file);
        }

        Map<String, Object> rsp = new HashMap<>(5);
        rsp.put("code", 200);
        rsp.put("data", list);
        rsp.put("count", list.size());
        System.out.println("rsp:" + rsp);
        return rsp;
    }

    @Override
    public Integer addEsFile(EsFile esFile) {
        try {
            String pathid = esFile.getPathid();
            String filepath = esFile.getFilepath();
            String extensionname = esFile.getExtensionname();
            List<Map<String, Object>> pathList = handlerService.findBySql("select * from tb_path where pathid = " + pathid + "");
            String parentname = MapUtil.getStr(pathList.get(0), "parentname");
            String downloadurl = parentname + filepath;
            String filecontent = EsFileServiceImpl.readFile(extensionname, downloadurl);
            if (StringUtils.isNotBlank(downloadurl)) {
                esFile.setDownloadurl(downloadurl);
            }
            if (StringUtils.isNotBlank(filecontent)) {
                esFile.setFilecontent(filecontent);
            }
            repository.save(esFile);
        } catch (Exception e) {
            return 0;
        }
        return 1;
    }

    public static String readFile(String type, String path) {
        System.out.println("readFile ==> path:" + path);
        File file = new File(path);
        StringBuilder str = new StringBuilder();
        switch (type) {
            case "doc":
            case "docx":
                try {
                    InputStream is = new FileInputStream(file);
                    XWPFDocument xwpfDocument = new XWPFDocument(is);
                    XWPFParagraph para;
                    Iterator<XWPFParagraph> iterator = xwpfDocument.getParagraphsIterator();
                    while (iterator.hasNext()) {
                        para = iterator.next();
                        str.append(para.getText()).append("\n");
                    }
                } catch (Exception e) {
                    System.out.println("doc/docx 异常:" + e.getMessage());
                }
                break;
            case "xls":
            case "xlsx":
                try {
                    InputStream is = new FileInputStream(file);
                    Workbook workbook = new XSSFWorkbook(is);
                    int sheetIndex = workbook.getActiveSheetIndex();
                    for (int i = 0; i < sheetIndex + 1; i++) {
                        Sheet sheet = workbook.getSheetAt(i);
                        String sheetName = sheet.getSheetName();
                        str.append(sheetName).append("\n");
                        // 行数
                        int rowNum = sheet.getPhysicalNumberOfRows();
                        for (int j = 0; j < rowNum; j++) {
                            Row row = sheet.getRow(j);
                            short lastCellNum = row.getLastCellNum();
                            for (int k = 0; k < lastCellNum; k++) {
                                str.append(row.getCell(k)).append("\t");
                            }
                            str.append("\n");
                        }
                        str.append("\n");
                    }
                } catch (Exception e) {
                    System.out.println("xlx/xlsx 异常:" + e.getMessage());
                }
                break;
            case "pdf":
                try {
                    PDFParser pdfParser = new PDFParser(new FileInputStream(file));
                    pdfParser.parse();
                    PDDocument pdDocument = pdfParser.getPDDocument();
                    int numberOfPages = pdDocument.getNumberOfPages();
                    //读取文本内容
                    PDFTextStripper pdfTextStripper = new PDFTextStripper();
                    //设置输出顺序
                    pdfTextStripper.setSortByPosition(true);
                    //起始页
                    pdfTextStripper.setStartPage(1);
                    pdfTextStripper.setEndPage(numberOfPages);
                    //文本内容
                    String text = pdfTextStripper.getText(pdDocument);
                    //换行符截取
                    String[] split = text.split("\n");
                    for (String s : split) {
                        str.append(s).append("\n");
                    }
                    pdDocument.close();
                } catch (Exception e) {
                    System.out.println("pdf 异常:" + e.getMessage());
                }
                break;
            default:
                System.out.println(" =====> readFile <===== 类型:" + type);
                break;
        }
        return StringUtils.isNotBlank(str.toString()) ? str.toString() : "";
    }

}
